package com.snack.scheduling;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.snack.entity.pojo.*;
import com.snack.service.*;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author huangfuhao
 * 该类用于进行过期库存更新，过期批次更新，昨日销售记录统计，昨日利润统计
 * @Date 2025/4/18
 */
@Component
public class DataProcessingScheduler {

    @Resource
    private BatchSnackService batchSnackService;
    @Resource
    private BatchService batchService;
    @Resource
    private StoreService storeService;
    @Resource
    private OrderService orderService;
    @Resource
    private OrderSnackService orderSnackService;
    @Resource
    private SnackService snackService;
    @Resource
    private ProfitService profitService;
    @Resource
    private SalesReportsService salesReportsService;

    // 每天凌晨2点执行数据统计和处理任务
    @Scheduled(cron = "0 0 2 * * ?")
    public void processDataTask() {
        // 在这里编写你的数据统计和处理逻辑
        System.out.println("执行数据统计和处理任务...");
    }

    // 创建定时任务，每天凌晨执行一次
    // 扫描 batch_snack 表，如果生产日期加上保质期小于当前日期（即已过期），则将状态改为已过期，并更新到数据库中。
    @Scheduled(cron = "0 0 0 * * ?")
    public void checkExpiredSnacks() {
        System.out.println("检查过期的零食...");

        // 获取当前日期
        Date currentDate = new Date();

        // 查询batch_snack表中状态为未过期的零食

        List<BatchSnack> batchSnacks = batchSnackService.list(new LambdaQueryWrapper<BatchSnack>()
                .eq(BatchSnack::getState, 0));
        //遍历查询结果，判断根据生产日期和保质期判断是否过期，保质期以月为单位

        for (BatchSnack batchSnack : batchSnacks) {
            LocalDate productionDate = batchSnack.getProductionDate();
            int shelfLife = batchSnack.getShelfLife();
            if (productionDate != null && shelfLife > 0) {
                LocalDate expirationDate = productionDate.plusMonths(shelfLife);
                if (expirationDate.isBefore(LocalDate.now())) {
                    // 如果过期，则将状态改为已过期，并更新到数据库中
                    batchSnack.setState(1);
                    batchSnackService.updateById(batchSnack);
                }
            }
        }
    }

    //创建一个定时任务，每天凌晨一点执行一次，用以查询批次所进的零食是否全部过期
    @Scheduled(cron = "0 0 1 * * ?")
    public void checkExpiredBatchSnacks() {
        //使用batchService查询batch表，获取status为0（即未全过期）的批次
        List<Batch> list = batchService.lambdaQuery().eq(Batch::getState, 0).list();
        //遍历list，查询其下属的batch_snack表，获取状态为0（未过期）的进货记录
        for (Batch batch : list) {
            List<BatchSnack> batchSnacks = batchSnackService.lambdaQuery().eq(BatchSnack::getBatchId, batch.getId()).eq(BatchSnack::getState, 0).list();
            //如果返回的集合为空，则将批次状态改为已全过期(1)，并更新到数据库中
            if (batchSnacks.isEmpty()) {
                batch.setState(1);
                batchService.updateById(batch);
            }
        }
    }


    //创建一个定时任务，每天凌晨0点30分执行一次，用以统计昨日销售记录和昨日利润
    @Scheduled(cron = "0 30 0 * * ?")
    public void calculateYesterdaySalesAndProfit() {
        System.out.println("统计昨日销售记录和昨日利润...");
        //获取昨日的开始时间和结束时间
        LocalDateTime yesterdayStart = LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime yesterdayEnd = LocalDateTime.now().minusDays(1).withHour(23).withMinute(59).withSecond(59).withNano(999999999);

        //先查询所有店铺获取每一个店铺id(使用storeService查询店铺列表)
        List<Store> stores = storeService.list();
        //抽出店铺id
        for (Store store : stores) {
            //根据店铺id查询昨日所有订单记录，统计销售额和利润
            Long storeId = store.getId();//拿到店铺id，开始计算昨日该店铺支出与收入
            Float cost = 0f;    //店铺昨日总指出
            Float revenue = 0f;//店铺昨日总收入

            //零食销售记录统计，其中Long指代零食表的id，Integer指代该零食销售数量
            HashMap<Integer, Integer> salesNum = new HashMap<>();

            //先查询昨日店铺下订单正常的订单记录，正常累计成本与收入，同时还要增加时间限制，查询昨天整天的订单记录
            for (Order order : orderService.lambdaQuery().eq(Order::getStoreId, storeId).eq(Order::getStatus, 0).ge(Order::getOrderDate, yesterdayStart).le(Order::getOrderDate, yesterdayEnd).list()) {
                Long orderId = order.getId();

                revenue = revenue + order.getTotalAmount();//拿到这笔订单的收入
                //通过订单id，查询order_snack表，查询相关零食、数量，再查询零食价格，进价。
                List<OrderSnack> list = orderSnackService.lambdaQuery().eq(OrderSnack::getOrderId, orderId).list();

                for (OrderSnack orderSnack : list) {
                    //开始统计这笔订单的支出与收入
                    Integer quantity = orderSnack.getQuantity();//获取到这笔订单这种零食数量
                    Snack snack = snackService.getById(orderSnack.getSnackId());
                    if (snack != null) {
                        snack.getCost();//拿到成本
                        cost += snack.getCost() * quantity;

                        //拿到零食id，若集合中已有该零食id，则将数量累加，否则将 snacksNum 中添加该零食id和数量。
                        Integer snackId = snack.getId();
                        if (salesNum.containsKey(snackId)) {
                            Integer num = salesNum.get(snackId);
                            salesNum.put(snackId, num + quantity);
                        } else {
                            salesNum.put(snackId, quantity);
                        }
                    }
                    //完成零食的成本统计
                }
                //到此，一笔状态正常的订单的支出与收入成功计入。
            }
            //到此，一家店铺的昨日销售记录和昨日利润计算完成。


            //这里记录店铺正常订单的销量情况，统计到salesReports表中
            //拿到统计出来的总销售额，查询salesNum当中数量最多的零食id和数量最少的零食id
            SalesReports salesReports = new SalesReports();
            //获取salesNum当中数量最多的零食id和数量最少的零食id
            if (!salesNum.isEmpty()) {
                Integer bestSellingProductId = Collections.max(salesNum.entrySet(), Map.Entry.comparingByValue()).getKey();
                Integer bestSales = salesNum.get(bestSellingProductId);
                Integer worstSellingProductId = Collections.min(salesNum.entrySet(), Map.Entry.comparingByValue()).getKey();
                Integer worstSales = salesNum.get(worstSellingProductId);
                salesReports.setStoreId(storeId);
                salesReports.setBestSellingProductId(bestSellingProductId);
                salesReports.setBestSales(bestSales);
                salesReports.setWorstSellingProductId(worstSellingProductId);
                salesReports.setWorstSales(worstSales);
                salesReports.setTotalSales(revenue);
                salesReports.setReportDate(LocalDate.now().minusDays(1));
                salesReportsService.save(salesReports);
            }

            //查询店铺下订单状态为库存销毁（状态为2）的订单记录，仅累计成本
            for (Order order : orderService.lambdaQuery().eq(Order::getStoreId, storeId).eq(Order::getStatus, 2).ge(Order::getOrderDate, yesterdayStart).le(Order::getOrderDate, yesterdayEnd).list()) {
                Long orderId = order.getId();
                //通过订单id，查询order_snack表，查询相关零食、数量，再查询零食价格，进价。
                List<OrderSnack> list = orderSnackService.lambdaQuery().eq(OrderSnack::getOrderId, orderId).list();
                for (OrderSnack orderSnack : list) {
                    //开始统计这笔订单的支出与收入
                    Integer quantity = orderSnack.getQuantity();//获取到这笔订单这种零食数量
                    Snack snack = snackService.getById(orderSnack.getSnackId());
                    if (snack != null) {
                        snack.getCost();//拿到成本
                        cost += snack.getCost() * quantity;
                    }
                }
                //到此，一笔库存销毁记录的支出成功计入
            }
            //计入昨日所有订单数据
            Profit profit = new Profit();//一家昨日的利润数据
            profit.setCost(cost); //计入成本
            profit.setRevenue(revenue);//计入收入
            profit.setProfit(revenue - cost);//计入利润
            //日期设置为昨天
            profit.setDate(LocalDate.now().minusDays(1));
            profit.setStoreId(storeId);
            profitService.save(profit);
        }
        //到此，完成所有店铺昨日销售数据统计
        System.out.println("统计结束");
    }


}
